﻿using System;
using System.Configuration;
using System.Net;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Threading;
using Def.Log;
using Microsoft.Win32;

namespace FrontDisplay.Weather
{
    public class WeatherPlugin : PluginBase
    {
        private readonly WeatherPage _weatherPage;
        private readonly DispatcherTimer _weatherTimer;
        private readonly WeatherControl _weatherControl;
        private const int TimerInterval = 30 * 60;
        private readonly Label _menuButton;
        private Hotkey _hotkey;
        private readonly Configuration _config;

        public WeatherPlugin()
        {
            _config = new Configuration();

            _weatherPage = new WeatherPage();
            _weatherControl = new WeatherControl
            {
                HorizontalAlignment = HorizontalAlignment.Right
            };
            _weatherControl.PreviewMouseLeftButtonDown += delegate { Navigation.Navigate(_weatherPage, Animation.MoveUp); };

            _weatherTimer = new DispatcherTimer();
            _weatherTimer.Tick += WeatherTimerTick;
            _weatherTimer.Interval = NextTimerInterval;

            _menuButton = new Label
            {
                FontSize = 200,
                FontFamily = new FontFamily("WebDings"),
                Content = "Ø"
            };
        }

        private static TimeSpan NextTimerInterval
        {
            get
            {
                return new TimeSpan(0, 0, TimerInterval - ((DateTime.Now.Minute * 60 + DateTime.Now.Second) % TimerInterval));
            }
        }

        public void UpdateDate()
        {
            _weatherControl.DateLabel.Text = DateTime.Now.Day.ToString();
            _weatherControl.MonthLabel.Text = DateTime.Now.ToString("d MMMM", Thread.CurrentThread.CurrentUICulture.DateTimeFormat).Remove(0, 2).Trim().ToLower();
        }

        private void WeatherTimerTick(object sender, EventArgs e)
        {
            UpdateDate();
            _weatherTimer.Interval = NextTimerInterval;
            GetCurrentWeather((p => _weatherControl.InvokedCall(UpdateWeather, p)));
        }

        private void UpdateWeather(WeatherInfo weather)
        {
            _weatherControl.WeatherLabel.Text = weather.ReadableTemperature;
            _weatherControl.WeatherConditionLabel.Content = weather.Image;
            
            _menuButton.Content = weather.Image;
            _menuButton.RenderTransform = new ScaleTransform(1.5, 1.5);
            _menuButton.Margin = new Thickness(0, 0, 0, 80);

            _weatherPage.UpdateWeather(weather);
        }

        //TODO: create possibility to add several cities.
        public City CurrentCity
        {
            get
            {
                return _config.City;
            }
        }

        public void GetCurrentWeather(Action<WeatherInfo> callback)
        {
//#if DEBUG
//            //TODO:
//            return;
//#endif

            var client = new WebClient();
            client.DownloadStringCompleted += DownloadWeatherCompleted;
            //TODO: check this. Should prevent getting info from cache. (nope, it didn't).
            client.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.NoCacheNoStore);
            client.DownloadStringAsync(CurrentCity.GetXmlUrl(_config.IsCelsius), callback);
        }

        private static void DownloadWeatherCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                Logger.Error(e.Error);
                return;
            }
            Action<WeatherInfo> callback = e.UserState as Action<WeatherInfo>;
            if (callback == null) return;

            Logger.Info("Weather updated");
            WeatherInfo weather = new WeatherInfo(e.Result);

            callback(weather);
        }

        private void SystemEventsPowerModeChanged(object sender, PowerModeChangedEventArgs e)
        {
            Logger.Info(string.Format("Power mode changed to {0}", e.Mode));
            if (e.Mode == PowerModes.Resume)
            {
                WeatherTimerTick(sender, EventArgs.Empty);
            }
        }

        public override string Title 
        {
            get { return Def.Localization.GetString("Weather.Weather"); }
        }

        public override UIElement MenuButton
        {
            get { return _menuButton; }
        }

        public override void Start()
        {
            _weatherTimer.Start();

            WeatherTimerTick(this, EventArgs.Empty);

            _hotkey = new Hotkey(_config.ShowWeatherHotkey)
            {
                Action = () => Navigation.Navigate(PageControl)
            };
            _hotkey.Register(Application.Current.MainWindow);

            InfoPage.Instance.ShowBottomInfo(BottomControl);
            IsActive = true;
            SystemEvents.PowerModeChanged += SystemEventsPowerModeChanged;
            Def.Localization.CultureChanged += LocalizationCultureChanged;
        }

        public override void Stop()
        {
            SystemEvents.PowerModeChanged -= SystemEventsPowerModeChanged;
            Def.Localization.CultureChanged -= LocalizationCultureChanged;
            if (_weatherTimer != null) _weatherTimer.Stop();
            if (_hotkey != null) _hotkey.Unregister();
        }

        private void LocalizationCultureChanged(System.Globalization.CultureInfo cultureInfo)
        {
            UpdateDate();
            _weatherPage.UpdateWeather();
        }

        public override Control PageControl
        {
            get { return _weatherPage; }
        }

        public override UIElement TopControl
        {
            get { return null; }
        }

        public override UIElement BottomControl
        {
            get { return _weatherControl; }
        }

        public override UIElement ParametersControl
        {
            get
            {
                ParametersPage parameters = new ParametersPage {SelectedCity = _config.City};

                if (_config.IsCelsius)
                {
                    parameters.CelsiusRadioButton.IsChecked = true;
                }
                else
                {
                    parameters.FahrenheitRadioButton.IsChecked = true;
                }

                return parameters;
            }
        }

        public override void SaveConfig(UIElement element)
        {
            ParametersPage parameters = element as ParametersPage;
            if (parameters == null) return;

            string oldCityCode = _config.City.Code;
            bool oldIsCelsius = _config.IsCelsius;

            _config.City = parameters.SelectedCity;
            _config.IsCelsius = (bool)parameters.CelsiusRadioButton.IsChecked;

            _hotkey.Value = _config.ShowWeatherHotkey;

            if ((_config.City.Code != oldCityCode) || (oldIsCelsius != _config.IsCelsius))
            {
                WeatherTimerTick(this, EventArgs.Empty);
            }

            _config.Save();
        }

        public override ApplicationSettingsBase Config
        {
            get
            {
                return _config;
            }
        }
    }
}
